package web.suzy.oj.manager.oj;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import web.suzy.oj.annotation.AccessEnum;
import web.suzy.oj.common.exception.StatusFailException;
import web.suzy.oj.common.exception.StatusForbiddenException;
import web.suzy.oj.common.exception.StatusNotFoundException;
import web.suzy.oj.config.NacosSwitchConfig;
import web.suzy.oj.config.SwitchConfig;
import web.suzy.oj.dao.discussion.DiscussionEntityService;
import web.suzy.oj.dao.problem.ProblemEntityService;
import web.suzy.oj.dao.user.UserAcproblemEntityService;
import web.suzy.oj.exception.AccessException;
import web.suzy.oj.pojo.entity.discussion.Discussion;
import web.suzy.oj.pojo.entity.problem.Problem;
import web.suzy.oj.pojo.entity.user.UserAcproblem;
import web.suzy.oj.pojo.vo.DiscussionVO;
import web.suzy.oj.shiro.AccountProfile;
import web.suzy.oj.utils.Constants;
import web.suzy.oj.utils.RedisUtils;
import web.suzy.oj.validator.AccessValidator;
import web.suzy.oj.validator.CommonValidator;

import java.util.List;

/**
 * YangSuzy 软件工作室
 * 类名: DiscussionManager
 * 描述: ---- 待定 -----
 * 功能: ---- 待定 -----
 *
 * @author YangSuzy
 * Date: 2022/12/10 22:43
 */
@Component
public class DiscussionManager {
    @Autowired
    private DiscussionEntityService discussionEntityService;

    @Autowired
    private ProblemEntityService problemEntityService;

    @Autowired
    private UserAcproblemEntityService userAcproblemEntityService;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private NacosSwitchConfig nacosSwitchConfig;

    @Autowired
    private AccessValidator accessValidator;

    @Autowired
    private CommonValidator commonValidator;

    /**
     * 方法名: getDiscussionList
     * 描述: 获取讨论列表
     *
     * @param limit       每页显示数目
     * @param currentPage 当前页
     * @param categoryId  分类ID
     * @param pid         题目ID
     * @param onlyMine    是否只读自己
     * @param keyword     关键字
     * @param admin       是否只读管理员
     * @return com.baomidou.mybatisplus.core.metadata.IPage<web.suzy.oj.pojo.entity.discussion.Discussion>
     * @date 2022/12/10 22:44
     * @auther YangSuzy
     **/
    public IPage<Discussion> getDiscussionList(
            Integer limit, Integer currentPage, Integer categoryId,
            String pid, boolean onlyMine, String keyword, boolean admin) {
        //新建分页对象
        IPage<Discussion> iPage = new Page<>(currentPage, limit);
        //获取登录的用户信息
        AccountProfile userRolesVo = (AccountProfile) SecurityUtils.getSubject().getPrincipal();
        //设置查询条件
        QueryWrapper<Discussion> discussionQueryWrapper = new QueryWrapper<>();
        if (categoryId != null) {
            discussionQueryWrapper.eq("category_id", categoryId);
        }
        if (!StringUtils.isEmpty(keyword)) {
            final String key = keyword.trim();
            //根据关键字模糊查询标题、作者、讨论ID、讨论描述
            discussionQueryWrapper.and(wrapper -> wrapper.like("title", key).or()
                    .like("author", key).or()
                    .like("id", key).or()
                    .like("description", key));
        }

        //获取用户角色，判断是否为管理员
        boolean isAdmin = SecurityUtils.getSubject().hasRole("root")
                || SecurityUtils.getSubject().hasRole("problem_admin")
                || SecurityUtils.getSubject().hasRole("admin");

        if (!StringUtils.isEmpty(pid)) {
            discussionQueryWrapper.eq("pid", pid);
        }

        discussionQueryWrapper
                .eq(!(admin && isAdmin), "status", 0)
                .orderByDesc("top_priority")
                .orderByDesc("create_time")
                .orderByDesc("like_num")
                .orderByDesc("view_num");

        if (onlyMine && userRolesVo != null) {
            discussionQueryWrapper.eq("uid", userRolesVo.getUid());
        }
        //根据查询条件获取讨论列表
        IPage<Discussion> discussionIPage = discussionEntityService.page(iPage, discussionQueryWrapper);
        List<Discussion> records = discussionIPage.getRecords();
        if (!CollectionUtils.isEmpty(records)) {
            for (Discussion discussion : records) {
                if (userRolesVo == null) {
                    discussion.setContent(null);
                } else if (!userRolesVo.getUid().equals(discussion.getUid())) {
                    discussion.setContent(null);
                }
            }
        }
        return discussionIPage;
    }

    /**
     * 方法名: getDiscussion
     * 描述: 根据讨论ID获取讨论详情
     *
     * @param did 讨论ID
     * @return web.suzy.oj.pojo.vo.DiscussionVO
     * @date 2022/12/10 23:02
     * @auther YangSuzy
     **/
    public DiscussionVO getDiscussion(Integer did) throws StatusNotFoundException, StatusForbiddenException, AccessException {
        //获取当前登录的用户
        AccountProfile userRolesVo = (AccountProfile) SecurityUtils.getSubject().getPrincipal();
        //判断是否为超级管理员
        boolean isRoot = SecurityUtils.getSubject().hasRole("root");
        //根据讨论ID获取讨论详情
        Discussion discussion = discussionEntityService.getById(did);
        //验证公共讨论区是否开启
        accessValidator.validateAccess(AccessEnum.PUBLIC_DISCUSSION);
        //判断是否存在登录用户信息（管理员可以通过后台直接查看讨论详情）
        String uid = null;
        if (userRolesVo != null) {
            uid = userRolesVo.getUid();
        }
        //获取讨论信息，根据uid判断该用户是否给该条讨论点过赞
        DiscussionVO discussionVo = discussionEntityService.getDiscussion(did, uid);
        if (discussionVo == null) {
            throw new StatusNotFoundException("对不起，该讨论不存在！");
        }
        if (discussionVo.getStatus() == 1) {
            throw new StatusForbiddenException("对不起，该讨论已被封禁！");
        }

        //浏览量+1
        UpdateWrapper<Discussion> discussionUpdateWrapper = new UpdateWrapper<>();
        discussionUpdateWrapper.setSql("view_num=view_num+1").eq("id", discussionVo.getId());
        discussionEntityService.update(discussionUpdateWrapper);
        discussionVo.setViewNum(discussionVo.getViewNum() + 1);

        return discussionVo;
    }

    /**
     * 方法名: addDiscussion
     * 描述: 发布讨论
     *
     * @param discussion 讨论
     * @return void
     * @date 2022/12/10 23:17
     * @auther YangSuzy
     **/
    public void addDiscussion(Discussion discussion) throws StatusFailException, StatusForbiddenException, StatusNotFoundException {
        //校验输入内容
        commonValidator.validateContent(discussion.getTitle(), "讨论标题", 255);
        commonValidator.validateContent(discussion.getDescription(), "讨论描述", 255);
        commonValidator.validateContent(discussion.getContent(), "讨论", 65535);
        commonValidator.validateNotEmpty(discussion.getCategoryId(), "讨论分类");

        //获取当前登录的用户
        AccountProfile userRolesVo = (AccountProfile) SecurityUtils.getSubject().getPrincipal();
        //判断用户角色
        boolean isRoot = SecurityUtils.getSubject().hasRole("root");
        boolean isProblemAdmin = SecurityUtils.getSubject().hasRole("problem_admin");
        boolean isAdmin = SecurityUtils.getSubject().hasRole("admin");
        //获取题目ID
        String problemId = discussion.getPid();
        if (problemId != null) {
            QueryWrapper<Problem> problemQueryWrapper = new QueryWrapper<>();
            problemQueryWrapper.eq("problem_id", problemId);
            int problemCount = problemEntityService.count(problemQueryWrapper);
            if (problemCount == 0) {
                throw new StatusNotFoundException("对不起，该题目不存在，无法发布题解!");
            }
        }

        //除管理员外，其它用户需要AC 20道题目以上才可发布讨论，同时限制一天只能发布5次
        if (!isRoot && !isProblemAdmin && !isAdmin) {
            QueryWrapper<UserAcproblem> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("uid", userRolesVo.getUid()).select("distinct pid");
            int userAcProblemCount = userAcproblemEntityService.count(queryWrapper);
            SwitchConfig switchConfig = nacosSwitchConfig.getSwitchConfig();
            if (userAcProblemCount < switchConfig.getDefaultCreateDiscussionACInitValue()) {
                throw new StatusForbiddenException("对不起，您暂时没有评论权限！请先通过至少" + switchConfig.getDefaultCreateDiscussionACInitValue() + "道题目!");
            }
            //从缓存中获取登录用户的讨论发布次数
            String lockKey = Constants.Account.DISCUSSION_ADD_NUM_LOCK.getCode() + userRolesVo.getUid();
            Integer num = (Integer) redisUtils.get(lockKey);
            if (num == null) {
                //第一次发布时设置计数缓存并保留一天
                redisUtils.set(lockKey, 1, 3600 * 24);
            } else if (num >= switchConfig.getDefaultCreateDiscussionDailyLimit()) {
                throw new StatusForbiddenException("对不起，您今天发布讨论次数已达上限【" + switchConfig.getDefaultCreateDiscussionDailyLimit() + "次】，请明天再发布吧！");
            } else {
                redisUtils.incr(lockKey, 1);
            }
        }
        //设置讨论信息
        discussion.setAuthor(userRolesVo.getUsername())
                .setAvatar(userRolesVo.getAvatar())
                .setUid(userRolesVo.getUid());

        if (isRoot) {
            discussion.setRole("root");
        } else if (isAdmin || isProblemAdmin) {
            discussion.setRole("admin");
        } else {
            //如果不是管理员，发布的讨论重置为非置顶状态
            discussion.setTopPriority(false);
        }

        boolean isOk = discussionEntityService.saveOrUpdate(discussion);
        if (!isOk) {
            throw new StatusFailException("发布失败，请重新尝试！");
        }
    }
}
